#include "DiffTool.h"
#include "CUtil.h"

using namespace std;

DiffTool::DiffTool()
{
	//This is the summary count information
	total_addedLines = total_deletedLines = total_modifiedLines = total_unmodifiedLines = 0;
	dup_addedLines = dup_deletedLines = dup_modifiedLines = dup_unmodifiedLines = 0;
	printDup = false;
}

//Rev-1		4/19/09   VN	  Mod041909VN: name the newly created file with its embedding file's filename.
//								The filename is used in the matching function for the comparison purpose
//								new file's filename = embedding file's filename + its default filename
//								(note: the filename contains *.*/ in its name)
int DiffTool::DiffToolWrapper(int argc, char *argv[])
{
	/*
		Diff Process:
		1. Parse Options
		2. Read Input Files
		3. Identify Duplicate files within same Baseline
		4. Match file pairs
		5. For each pair
			5a. Run Counter on the pair to get SLOC
			5b. Run Diff functionality on SLOC
		6. For unmatched files run counter then diff against null set
		7. Print all data (count,diff, duplicate results)
	*/
	BaselineFileName1 = BASELINE_INF1;
	BaselineFileName2 = BASELINE_INF2;
	match_threshold = 60; //Default Modified Lines Threshold
	use_SLOC = true;
	use_CommandLine = false; 

	//Parse the command line input
	parse_commandLine(argc,argv);

	cout << "Reading source files...";
	if (!handleReadInputFiles())
		return 0;//If it failed just die silently
	cout << ".......................DONE" << endl;

	// Code for replacing @@ in ClearCase issue, add code here
	// End of Code for...

//  Mod041909VN: the following commented code is moved to the new position
//	matchBaseLines();
	//matchedFilesList now contains the complete match file pairs
	//Show Pairs
	//PrintMatchedPairs();
	//Count Files to get SLOC

	// Count BaselineA and prepare SLOC for differencing
	cout << "Performing files analysis and counting: A";
	findDuplicateFiles(SourceFile, duplicateFilesInA1, duplicateFilesInA2);
	ProcessSourceList(true);//BaselineA

	//  Print the UCC results for BaselineA (SLOC counts and complexity counts)
	PrintResults(true, "Baseline-A-", &duplicateFilesInA2);
	PrintComplexityResults(true, "Baseline-A-");
	PrintResults(true, "Duplicates-A-", &duplicateFilesInA2, false);
	PrintComplexityResults(true, "Duplicates-A-", true);
	PrintDuplicateSummary(true, "Duplicates-A-");

	// Reset the counts for BaselineB
	ResetCounterCounts();

	// Count BaselineB and prepare SLOC for differencing
	cout << "Performing files analysis and counting: B";
	findDuplicateFiles(SourceFileB, duplicateFilesInB1, duplicateFilesInB2);
	ProcessSourceList(false);//BaselineB

	//  Print the UCC results for BaselineB (SLOC counts and complexity counts)
	PrintResults(false,"Baseline-B-", &duplicateFilesInB2);
	PrintComplexityResults(false, "Baseline-B-");
	PrintResults(false, "Duplicates-B-", &duplicateFilesInB2, false);
	PrintComplexityResults(false, "Duplicates-B-", true);
	PrintDuplicateSummary(false, "Duplicates-B-");

	cout << "Performing files comparison...";
	matchBaseLines();
	PrintMatchedPairs();
	processPairs();
	cout << "................DONE" << endl;

	cout << "Generating results to files...";
	printResults();
	cout << "................DONE" << endl;
	return 1;
}

// Results of the matching pairs of files are stored in MatchingPairs.txt in a formatted 
// manner.
void DiffTool::PrintMatchedPairs()
{
	ofstream pairFile;

	pairFile.open(MATCH_PAIRS_OUTFILE, ofstream::out);
	if (!pairFile.is_open())
	{
		string err = "Error: Failed to open matched file pairs summary output file (";
		err += MATCH_PAIRS_OUTFILE;
		err += ")";
		cout << err << endl;
		CUtil::AddError(err);
		return;
	}

	CUtil::PrintFileHeader(pairFile, "MATCHED FILE PAIRS");
	pairFile << endl;
	pairFile.setf(ofstream::left);
	pairFile.width(45);
	pairFile << "Baseline A";
	pairFile.unsetf(ofstream::left);
	pairFile.width(5);
	pairFile << "  |  ";
	pairFile.width(3);
	pairFile.setf(ofstream::left);
	pairFile.width(45);
	pairFile << "Baseline B";
	pairFile << endl;
	for (int y = 0; y < 90; y++)
		pairFile << "-";

	// Print the results of matching pairs in the file in formatted manner.
	for (MatchingType::iterator myI = matchedFilesList.begin(); myI != matchedFilesList.end(); myI++)
	{
		string fileA, fileB;
		if ((*myI).second.first == NULL)
		{
			fileA = "NA";
		}
		else
		{
			fileA = (*myI).second.first->second.file_name;
		}
		if ((*myI).second.second == NULL)
		{
			fileB = "NA";
		}
		else
		{
			fileB = (*myI).second.second->second.file_name;
		}

		pairFile << endl;
		pairFile.setf(ofstream::left);
		pairFile.width(45);
		pairFile << fileA;
		pairFile.unsetf(ofstream::left);
		pairFile.width(5);
		pairFile << "  |  ";
		pairFile.setf(ofstream::left);
		pairFile.width(45);
		pairFile << fileB;
	}
	pairFile.close();
}

//Rev-2		7/5/09   VN	  Mod070509VN: moved the first four lines to the method DiffToolWrapper() 
//                        Purpose: after completing processing the baseline 1, print complexity results 
//                                 and clear the counts to process the baseline 2.
void DiffTool::printResults()
{
	//Print UCC stuff
//	PrintResults(true,"Duplicates-A-", &duplicateFilesInA);
//	PrintResults(false,"Duplicates-B-", &duplicateFilesInB);
//	PrintResults(true,"Baseline-A-");
//	PrintResults(false,"Baseline-B-");

	//Now Diff Results
	outfile_diff_results.open(DIFF_OUTFILE,ofstream::out);
	if (!outfile_diff_results.is_open())
	{
		string err = "Error: Failed to open diff results output file (";
		err += DIFF_OUTFILE;
		err += ")";
		cout << err << endl;
		CUtil::AddError(err);
		return;
	}
	outfile_diff_csv.open(DIFF_OUTFILE_CSV,ofstream::out);
	if (!outfile_diff_csv.is_open())
	{
		string err = "Error: Failed to open diff results output file (";
		err += DIFF_OUTFILE_CSV;
		err += ")";
		cout << err << endl;
		CUtil::AddError(err);
		return;
	}
	if (printDup)
	{
		string fName = "Duplicates-";
		fName += DIFF_OUTFILE;
		dup_outfile_diff_results.open(fName.c_str(),ofstream::out);
		if (!dup_outfile_diff_results.is_open())
		{
			string err = "Error: Failed to open duplicates diff results output file (";
			err += fName;
			err += ")";
			cout << err << endl;
			CUtil::AddError(err);
			return;
		}
		fName = "Duplicates-";
		fName += DIFF_OUTFILE_CSV;
		dup_outfile_diff_csv.open(fName.c_str(),ofstream::out);
		if (!dup_outfile_diff_csv.is_open())
		{
			string err = "Error: Failed to open duplicates diff results output file (";
			err += fName;
			err += ")";
			cout << err << endl;
			CUtil::AddError(err);
			return;
		}
	}
	output_intro_hdr_comp();//Prints General Diff Header
	string filenameA, filenameB, lang;
	bool useDup;
	lang = DEF_LANG_NAME;
	for (MatchingType::iterator myI = matchedFilesList.begin(); myI != matchedFilesList.end(); myI++)
	{
		//Print pair results
		//Select the filename, choose the baselineA unless this one was only in baselineB
		filenameA = ((*myI).second.first != NULL) ? (*myI).second.first->second.file_name : "NA";
		filenameB = ((*myI).second.second != NULL) ? (*myI).second.second->second.file_name : "NA";

		if (((*myI).first.addedLines == 0) && ((*myI).first.deletedLines == 0)
			&& ((*myI).first.modifiedLines == 0) && ((*myI).first.unmodifiedLines == 0)) 
		{
			//lang = DEF_LANG_NAME;
			continue; // do not print out if the file is empty or file not supported
		}
		else
		{
			if ((*myI).second.first != NULL)
				lang =  GetLangName((*myI).second.first->second.class_type);
			else lang =  GetLangName((*myI).second.second->second.class_type);
		}

		useDup = false;
		if ((*myI).second.first != NULL)
		{
			if ((*myI).second.first->second.duplicate)
				useDup = true;
		}
		if ((*myI).second.second != NULL)
		{
			if ((*myI).second.second->second.duplicate)
			{
				if ((*myI).second.first == NULL)
					useDup = true;
			}
			else
				useDup = false;
		}

		PrintDiffFileResults(filenameA, filenameB, (*myI).first, lang, useDup);
	}
	//Print Summary	
	PrintDiffResultSummary();
	outfile_diff_results.close();
	outfile_diff_csv.close();
	if (printDup)
	{
		dup_outfile_diff_results.close();
		dup_outfile_diff_csv.close();
	}
}

/*******************************
PrintDiffResultSummary

Description
Prints the final summary of diff counts for all the files in this batch run.
*******************************/
void DiffTool::PrintDiffResultSummary ()
{
	outfile_diff_results << endl << endl;
	string myCats[] = {"New", "Deleted", "Modified", "Unmodified"};
	int numCats = 4;
	for (int ti = 0; ti < numCats; ti++)
	{
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << "Total";
		outfile_diff_results.unsetf(ofstream::left);
		if ((ti + 1) < numCats)
		{
			outfile_diff_results.width(3);
			outfile_diff_results << "| ";
		}
	}
	outfile_diff_results << endl;
	for (int ti = 0; ti < numCats; ti++)
	{
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << myCats[ti];
		outfile_diff_results.unsetf(ofstream::left);
		if ((ti + 1) < numCats)
		{
			outfile_diff_results.width(3);
			outfile_diff_results << "| ";
		}
	}
	outfile_diff_results << endl;
	for (int ti = 0; ti < numCats; ti++)
	{
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << "Lines";
		outfile_diff_results.unsetf(ofstream::left);
		if ((ti + 1) < numCats)
		{
			outfile_diff_results.width(3);
			outfile_diff_results << "| ";
		}
	}
	outfile_diff_results << endl;
	for (int y = 0; y < 73; y++)
		outfile_diff_results << BAR_S;
	outfile_diff_results << endl;

	outfile_diff_csv << endl << "Total New Lines,Total Deleted Lines,Total Modified Lines,Total Unmodified Lines" << endl;
	
	outfile_diff_results.setf(ofstream::left);
	outfile_diff_results.width(15);
	outfile_diff_results << this->total_addedLines;
	
	outfile_diff_csv << this->total_addedLines;
	
	outfile_diff_results.unsetf(ofstream::left);  
	outfile_diff_results.width(3);
	outfile_diff_results << "| ";
	outfile_diff_results.setf(ofstream::left);
	outfile_diff_results.width(15);
	outfile_diff_results << this->total_deletedLines;

	outfile_diff_csv << "," << this->total_deletedLines;

	outfile_diff_results.unsetf(ofstream::left);  
	outfile_diff_results.width(3);
	outfile_diff_results << "| ";
	outfile_diff_results.setf(ofstream::left);
	outfile_diff_results.width(15);
	outfile_diff_results << this->total_modifiedLines;

	outfile_diff_csv << "," << this->total_modifiedLines;

	outfile_diff_results.unsetf(ofstream::left);  
	outfile_diff_results.width(3);
	outfile_diff_results << "| ";
	outfile_diff_results.setf(ofstream::left);
	outfile_diff_results.width(15);
	outfile_diff_results << this->total_unmodifiedLines;
	
	outfile_diff_csv << "," << this->total_unmodifiedLines << endl;
	
	outfile_diff_results << endl << endl;

	if (printDup)
	{
		dup_outfile_diff_results << endl << endl;
		for (int ti = 0; ti < numCats; ti++)
		{
			dup_outfile_diff_results.setf(ofstream::left);
			dup_outfile_diff_results.width(15);
			dup_outfile_diff_results << "Total";
			dup_outfile_diff_results.unsetf(ofstream::left);
			if ((ti + 1) < numCats)
			{
				dup_outfile_diff_results.width(3);
				dup_outfile_diff_results << "| ";
			}
		}
		dup_outfile_diff_results << endl;
		for (int ti = 0; ti < numCats; ti++)
		{
			dup_outfile_diff_results.setf(ofstream::left);
			dup_outfile_diff_results.width(15);
			dup_outfile_diff_results << myCats[ti];
			dup_outfile_diff_results.unsetf(ofstream::left);
			if ((ti + 1) < numCats)
			{
				dup_outfile_diff_results.width(3);
				dup_outfile_diff_results << "| ";
			}
		}
		dup_outfile_diff_results << endl;
		for (int ti = 0; ti < numCats; ti++)
		{
			dup_outfile_diff_results.setf(ofstream::left);
			dup_outfile_diff_results.width(15);
			dup_outfile_diff_results << "Lines";
			dup_outfile_diff_results.unsetf(ofstream::left);
			if ((ti + 1) < numCats)
			{
				dup_outfile_diff_results.width(3);
				dup_outfile_diff_results << "| ";
			}
		}
		dup_outfile_diff_results << endl;
		for (int y = 0; y < 73; y++)
			dup_outfile_diff_results << BAR_S;
		dup_outfile_diff_results << endl;

		dup_outfile_diff_csv << endl << "Total New Lines,Total Deleted Lines,Total Modified Lines,Total Unmodified Lines" << endl;

		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << this->dup_addedLines;

		dup_outfile_diff_csv << this->dup_addedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);  
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << this->dup_deletedLines;

		dup_outfile_diff_csv << "," << this->dup_deletedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);  
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << this->dup_modifiedLines;

		dup_outfile_diff_csv << "," << this->dup_modifiedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);  
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << this->dup_unmodifiedLines;

		dup_outfile_diff_csv << "," << this->dup_unmodifiedLines << endl;

		dup_outfile_diff_results << endl << endl;
	}
}

/**********************************
PrintDiffFileResults

Description
Prints intermediate file results for the diff counter.
Takes filename = the current file that is being operated on

**********************************/
void DiffTool::PrintDiffFileResults(string &filenameA, string &filenameB, resultStruct &myResults, string &lang, bool useDup)
{
	string modType;

	if (!useDup)
	{
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << myResults.addedLines;

		outfile_diff_csv << myResults.addedLines;

		outfile_diff_results.unsetf(ofstream::left);
		outfile_diff_results.width(3);
		outfile_diff_results << "| ";
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << myResults.deletedLines; //VN: modified from addedLines

		outfile_diff_csv << "," << myResults.deletedLines;

		outfile_diff_results.unsetf(ofstream::left);
		outfile_diff_results.width(3);
		outfile_diff_results << "| ";
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << myResults.modifiedLines;

		outfile_diff_csv << "," << myResults.modifiedLines;

		outfile_diff_results.unsetf(ofstream::left);
		outfile_diff_results.width(3);
		outfile_diff_results << "| ";
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << myResults.unmodifiedLines;

		outfile_diff_csv << "," << myResults.unmodifiedLines;

		outfile_diff_results.unsetf(ofstream::left);
		outfile_diff_results.width(3);
		outfile_diff_results << "| ";
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);

		if (myResults.deletedLines==0 && myResults.unmodifiedLines==0 && myResults.modifiedLines==0)
			modType = "Add";	
		else if (myResults.addedLines==0 && myResults.unmodifiedLines==0 && myResults.modifiedLines==0)
			modType = "Del";
		else if (myResults.addedLines==0 && myResults.deletedLines==0 && myResults.modifiedLines==0)
			modType = "Unmod";
		else modType = "Mod";

		outfile_diff_csv << "," << modType;
		outfile_diff_csv << ",\"" << lang << "\"";

		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		if (filenameB.compare("NA") != 0)
		{
			outfile_diff_results << filenameB;
		}
		else
		{
			outfile_diff_results << filenameA;
		}

		outfile_diff_csv << ",\"" + filenameA + "\",\"" + filenameB + "\"";
		outfile_diff_csv << endl;

		outfile_diff_results.unsetf(ofstream::left);
		outfile_diff_results << endl;
	}
	else
	{
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << myResults.addedLines;

		dup_outfile_diff_csv << myResults.addedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << myResults.deletedLines; //VN: modified from addedLines

		dup_outfile_diff_csv << "," << myResults.deletedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << myResults.modifiedLines;

		dup_outfile_diff_csv << "," << myResults.modifiedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << myResults.unmodifiedLines;

		dup_outfile_diff_csv << "," << myResults.unmodifiedLines;

		dup_outfile_diff_results.unsetf(ofstream::left);
		dup_outfile_diff_results.width(3);
		dup_outfile_diff_results << "| ";
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);

		if (myResults.deletedLines==0 && myResults.unmodifiedLines==0 && myResults.modifiedLines==0)
			modType = "Add";	
		else if (myResults.addedLines==0 && myResults.unmodifiedLines==0 && myResults.modifiedLines==0)
			modType = "Del";
		else if (myResults.addedLines==0 && myResults.deletedLines==0 && myResults.modifiedLines==0)
			modType = "Unmod";
		else modType = "Mod";

		dup_outfile_diff_csv << "," << modType;
		dup_outfile_diff_csv << ",\"" << lang << "\"";

		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		if (filenameB.compare("NA") != 0)
		{
			dup_outfile_diff_results << filenameB;
		}
		else
		{
			dup_outfile_diff_results << filenameA;
		}

		dup_outfile_diff_csv << ",\"" + filenameA + "\",\"" + filenameB + "\"";
		dup_outfile_diff_csv << endl;

		dup_outfile_diff_results.unsetf(ofstream::left);
		dup_outfile_diff_results << endl;
	}
}

/****************************************************************
output_intro_hdr_comp
Prints the DIFF TOOL Header to the output file for the diff results.
****************************************************************/
void DiffTool::output_intro_hdr_comp()
{
	string myCats[] = {"New", "Deleted", "Modified", "Unmodified", "Module"};
	int numCats = 5;

	CUtil::PrintFileHeader(outfile_diff_results, "SOURCE CODE DIFFERENTIAL RESULTS");
	CUtil::PrintFileHeader(outfile_diff_csv, "SOURCE CODE DIFFERENTIAL RESULTS");
	if (printDup)
	{
		CUtil::PrintFileHeader(dup_outfile_diff_results, "SOURCE CODE DIFFERENTIAL RESULTS");
		CUtil::PrintFileHeader(dup_outfile_diff_csv, "SOURCE CODE DIFFERENTIAL RESULTS");
	}

	for (int i = 0; i < numCats; i++)
	{
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << myCats[i];
		outfile_diff_results.unsetf(ofstream::left);
		if ((i+1) < numCats)
		{
			outfile_diff_results.width(3);
			outfile_diff_results << " | ";
		}
	}
	outfile_diff_results << endl;
	for (int i = 0; i < numCats-1; i++)
	{
		outfile_diff_results.setf(ofstream::left);
		outfile_diff_results.width(15);
		outfile_diff_results << "Lines";
		outfile_diff_results.unsetf(ofstream::left);
		outfile_diff_results.width(3);
		outfile_diff_results << " | ";
	}
	outfile_diff_results.setf(ofstream::left);
	outfile_diff_results.width(15);
	outfile_diff_results << "Name";
	outfile_diff_results.unsetf(ofstream::left);
	outfile_diff_results << endl;
	for (int y = 0; y < 120; y++)
		outfile_diff_results << BAR_S;
	outfile_diff_results << endl;
	
	outfile_diff_csv << "New Lines,Deleted Lines,Modified Lines,Unmodified Lines,Modification Type,Language,Module A,Module B" << endl;

	if (printDup)
	{
		for (int i = 0; i < numCats; i++)
		{
			dup_outfile_diff_results.setf(ofstream::left);
			dup_outfile_diff_results.width(15);
			dup_outfile_diff_results << myCats[i];
			dup_outfile_diff_results.unsetf(ofstream::left);
			if ((i+1) < numCats)
			{
				dup_outfile_diff_results.width(3);
				dup_outfile_diff_results << " | ";
			}
		}
		dup_outfile_diff_results << endl;
		for (int i = 0; i < numCats-1; i++)
		{
			dup_outfile_diff_results.setf(ofstream::left);
			dup_outfile_diff_results.width(15);
			dup_outfile_diff_results << "Lines";
			dup_outfile_diff_results.unsetf(ofstream::left);
			dup_outfile_diff_results.width(3);
			dup_outfile_diff_results << " | ";
		}
		dup_outfile_diff_results.setf(ofstream::left);
		dup_outfile_diff_results.width(15);
		dup_outfile_diff_results << "Name";
		dup_outfile_diff_results.unsetf(ofstream::left);
		dup_outfile_diff_results << endl;
		for (int y = 0; y < 120; y++)
			dup_outfile_diff_results << BAR_S;
		dup_outfile_diff_results << endl;

		dup_outfile_diff_csv << "New Lines,Deleted Lines,Modified Lines,Unmodified Lines,Modification Type,Language,Module A,Module B" << endl;
	}
}

/**
	Executes the actual Diff Functionality on the mapped pairs.
	Assumes that the SLOC lines have been put int the mySLOCLines object in the results object of each file.

	Rev-1  5/12/09	VN	Mod051209AS: Included memory leak fixes provided by Aaron Shumate of NGC
*/
void DiffTool::processPairs()
{
	srcLineVector* myNullFile = new srcLineVector();
	srcLineVector* firstFile;
	srcLineVector* secondFile;
	bool isDup;
	for (MatchingType::iterator myI = matchedFilesList.begin(); myI != matchedFilesList.end(); myI++)
	{
		//Each source file elements results object has a mySLOCLines object with the SLOC to be diffed
		CmpMngr myDiffManager;
		firstFile = myNullFile;
		secondFile = myNullFile;
		isDup = false;
		if ((*myI).second.first != NULL)
		{
			firstFile = &(*myI).second.first->second.mySLOCLines;
			if ((*myI).second.first->second.duplicate)
				isDup = true;
		}
		if ((*myI).second.second != NULL)
		{
			secondFile = &(*myI).second.second->second.mySLOCLines;
			if ((*myI).second.second->second.duplicate)
			{
				if ((*myI).second.first == NULL)
					isDup = true;
			}
			else
				isDup = false;
		}
		//This makes sure that if one of the files was unmatched it will just compare it against an empty set
		myDiffManager.compare(firstFile, secondFile, match_threshold);
		if (isDup)
		{
			printDup = true;
			this->dup_addedLines += (*myI).first.addedLines = myDiffManager.nAddedLines;
			this->dup_deletedLines += (*myI).first.deletedLines = myDiffManager.nDeletedLines;
			this->dup_modifiedLines += (*myI).first.modifiedLines = myDiffManager.nChangedLines;
			this->dup_unmodifiedLines += (*myI).first.unmodifiedLines = myDiffManager.nNochangedLines;
		}
		else
		{
			this->total_addedLines += (*myI).first.addedLines = myDiffManager.nAddedLines;
			this->total_deletedLines += (*myI).first.deletedLines = myDiffManager.nDeletedLines;
			this->total_modifiedLines += (*myI).first.modifiedLines = myDiffManager.nChangedLines;
			this->total_unmodifiedLines += (*myI).first.unmodifiedLines = myDiffManager.nNochangedLines;
		}
	}
	delete myNullFile; //Mod051209AS
}

// Description: 
// Matches each file between the two baselines with the best possible match.
//	1. Build a preference list for each file
//		1a. Preference list is an ordered list of files in the other baseline in order of the quality of the match
//	2. Run the gale shapely algorithm to create a matching
//	3. Files that are unmatched will be paired with an empty file to be compared to
// Revision  Date     Author  Modification
// Rev-1     Fall 08  HG      Original author
// Rev-2     Fall 08  VN      Two files are matched if and only if they have 
//                              the same sort name.
// Rev-3     5/12/09  VN	  Mod051209AS: Included memory leak fixes provided by Aaron Shumate of NGC
void DiffTool::matchBaseLines()
{
	//List of files each with a preferences list
	BaselinePreferenceMapType BaseAPrefs,BaseBPrefs;
	//Go through the SourceFile list and compare each to SourceFileB to generate a preference
	//BaselineA
	for (SourceFileList::iterator i = SourceFile.begin(); i != SourceFile.end(); i++)
	{
		PreferenceMapType* myBPrefs = new PreferenceMapType;
		//BaselineB
		for (SourceFileList::iterator j = SourceFileB.begin(); j != SourceFileB.end(); j++)
		{
			//need to check if this guy has a preference list, if so use it, if not create it
			PreferenceMapType* myAPrefs;
			BaselinePreferenceMapType::iterator sfBIterator = BaseBPrefs.find(&(*j));
			if (sfBIterator != BaseBPrefs.end())
			{	//Already Exists, use it
				myAPrefs = (*sfBIterator).second;
			}
			else
			{	//Does not exist create one
				myAPrefs = new PreferenceMapType;
			}
			//compare this guy to the guy from A
			int ourPreference = compareFileNames((*i).second.file_name,(*j).second.file_name);
			//update preference lists for both guys
			PreferenceStruct myBPS, myAPS;
			myBPS.fileElement = &(*j);
			myBPS.value = ourPreference;
			myAPS.fileElement = &(*i);
			myAPS.value = ourPreference;
			myBPrefs->push_back(myBPS);
			myAPrefs->push_back(myAPS);
			sort(myAPrefs->begin(),myAPrefs->end(),CustomCMP());//Make sure its sorted by preference value
			BaseBPrefs[&(*j)] = myAPrefs;//Save the new values for the BaseBPrefs
		}
		sort(myBPrefs->begin(),myBPrefs->end(),CustomCMP());//Make sure its sorted by preference value
		BaseAPrefs[&(*i)] = myBPrefs;//Save the new values for the BaseAPrefs
	}
	//At this point we have a complete sorted preference list for all pairs
	//We will want to match preferences that have the smallest value as it is actually the value of optimal alignment
	
	//Now do gale shapley...
	//MatchingType matchedFilesList - to hold the final info
	
	list<SourceFileElement*> FreeBaseAList;
	map<SourceFileElement*,PreferenceMapType::iterator> NextSelectionMapBaseA;
	BaselineFileMapType BaseAMatches,BaseBMatches;
	
	for (BaselinePreferenceMapType::iterator myI = BaseAPrefs.begin(); myI != BaseAPrefs.end(); myI++)
	{
		BaseAMatches[(*myI).first] = NULL;
		FreeBaseAList.push_back((*myI).first);
		NextSelectionMapBaseA.insert(make_pair((*myI).first,(*myI).second->begin()));
	}
	
	//Do this for completeness later on
	for (BaselinePreferenceMapType::iterator myI = BaseBPrefs.begin(); myI != BaseBPrefs.end(); myI++)
	{
		BaseBMatches[(*myI).first] = NULL;
	}
	while (!FreeBaseAList.empty())
	{
		//Find a file in baseA that is unmatched and has not tried to match against all of files in B
		list<SourceFileElement*>::iterator myAFile = FreeBaseAList.begin();
		PreferenceMapType::iterator myBFile = NextSelectionMapBaseA[(*myAFile)];		
		
		if (myBFile == BaseAPrefs[(*myAFile)]->end())
		{
			//It has checked all and is not a good match, match to null
			BaseAMatches[(*myAFile)] = NULL;
			//Remove it from the "Free" list
			FreeBaseAList.pop_front();
			continue; 
		}
		
		//If BFile is unmatched, then pair them...
		BaselineFileMapType::iterator mLocation = BaseBMatches.find((*myBFile).fileElement);
		if (mLocation == BaseBMatches.end() || (*mLocation).second == NULL)
		{	//Not matched up, pair it!
			// VN: If the filename is the same, match them
			if (CUtil::ExtractFilename((*myBFile).fileElement->second.file_name).compare(
				CUtil::ExtractFilename((*myAFile)->second.file_name)) == 0)
			{
				BaseAMatches[(*myAFile)] = (*myBFile).fileElement;
				BaseBMatches[(*myBFile).fileElement] = (*myAFile);
			}
			else
			{	// otherwise, match them to NULL
				BaseAMatches[(*myAFile)] = NULL;
				BaseBMatches[(*myBFile).fileElement] = NULL;
			}
			//Now increase NextSelection for A as it has now examined this preference file entry
			NextSelectionMapBaseA[(*myAFile)] = ++myBFile;
			//Remove this A file from free list.
			FreeBaseAList.pop_front();
		}
		else
		{	//This preference is already matched, check stability
			SourceFileElement* myAFilePrime = (*mLocation).second;//This is the file in A that B is matched to right now
			//Check to see if FileB prefers AFile over AFilePrime
			bool foundAPrimeFirst = false;
			for (PreferenceMapType::iterator myI = BaseBPrefs[(*myBFile).fileElement]->begin();
				myI != BaseBPrefs[(*myBFile).fileElement]->end(); myI++)
			{
				if ((*myI).fileElement == myAFilePrime)
				{	//Found the Prime
					foundAPrimeFirst = true;
					break;
				}
				else if ((*myI).fileElement == (*myAFile))
				{	//Found the A File
					break;
				}
			}
			if (foundAPrimeFirst)
			{	//File APrime and FileB are a better match, keep it that way
				//Now FileA remains unmatched but increment its next selection
				NextSelectionMapBaseA[(*myAFile)] = ++myBFile;
				//Now check to see if it has checked all the files, if so match it with null
				if (myBFile == BaseAPrefs[(*myAFile)]->end())
				{
					//It has checked all and is not a good match, match to null
					BaseAMatches[(*myAFile)] = NULL;
					//Remove it from the "Free" list
					FreeBaseAList.pop_front();
				}
			}
			else
			{	//FileB and FileA are better matches....
				//Free FileAPrime or match it to null
				BaseAMatches[myAFilePrime] = NULL;
				//Now check to see if it has checked all the files
				if (NextSelectionMapBaseA[myAFilePrime] != BaseAPrefs[myAFilePrime]->end())
				{
					//Has not checked all, put back on free list
					FreeBaseAList.push_back(myAFilePrime);
				}

				// Mod by VN: if FileA and FileB have the same name, match them
				if (CUtil::ExtractFilename((*myBFile).fileElement->second.file_name).compare(
					CUtil::ExtractFilename((*myAFile)->second.file_name)) == 0)
				{
					//Match FileA and FileB
					BaseAMatches[(*myAFile)] = (*myBFile).fileElement;
					BaseBMatches[(*myBFile).fileElement] = (*myAFile);
				}
				else
				{	//Match FileA and FileB to NULL
					BaseAMatches[(*myAFile)] = NULL;
					BaseBMatches[(*myBFile).fileElement] = NULL;
				}
				NextSelectionMapBaseA[(*myAFile)] = ++myBFile;
				//Remove this A file from free list.
				FreeBaseAList.pop_front();				
			}
		}
	}

	//Now attempt to match unmatched files by checking content
	for (BaselineFileMapType::iterator i = BaseAMatches.begin(); i != BaseAMatches.end(); i++)
	{
		if ((*i).second == NULL)
		{
			for (BaselineFileMapType::iterator j = BaseBMatches.begin(); j != BaseBMatches.end(); j++)
			{
				if ((*j).second == NULL)
				{
					SourceFileElement* fileA = (*i).first;
					SourceFileElement* fileB = (*j).first;
					if (fileA->first.size() == fileB->first.size())
					{	// VN: this helps run a bit faster
						vector<lineElement>::iterator baseLine = fileA->first.begin();
						vector<lineElement>::iterator compareLine = fileB->first.begin();		
						bool filesmatched = true;
						while (baseLine != fileA->first.end() && compareLine != fileB->first.end())
						{
							if ((*baseLine).line.compare((*compareLine).line) != 0)
							{
								filesmatched = false;
								break;
							}
							baseLine++;
							compareLine++;
						}
						if (baseLine != fileA->first.end() || compareLine != fileB->first.end())
						{
							filesmatched = false;
						}
						if (filesmatched)
						{
							//Match files
							(*i).second = fileB;
							(*j).second = fileA;
						}
					}
				}
			}
		}
	}

	//Ok now we have our matches in BaseAMatches
	//MatchedFilePair
	//matchedFilesList
	//Now go through all files in A, if matched create pair, if unmatched pair with null
	//Then go through B, if Matched, ignore since already added from A, if unmatched pair with null
	//Process ordering based on input lists
	for (SourceFileList::iterator i = SourceFile.begin(); i != SourceFile.end(); i++)
	{
		//Get the corresponding match
		BaselineFileMapType::iterator mLocation = BaseAMatches.find(&(*i));
		if (mLocation != BaseAMatches.end())
		{
			resultStruct myResults;
			matchedFilesList.push_back(make_pair(myResults,(*mLocation)));
		}
	}

	for (SourceFileList::iterator i = SourceFileB.begin(); i != SourceFileB.end(); i++)
	{
		//Get the corresponding match
		BaselineFileMapType::iterator mLocation = BaseBMatches.find(&(*i));
		if (mLocation != BaseBMatches.end() && mLocation->second == NULL)
		{
			resultStruct myResults;
			MatchedFilePair myPair = make_pair((*mLocation).second, (*mLocation).first);
			matchedFilesList.push_back(make_pair(myResults,myPair));
		}
	}
	//At this point we have the complete match set in matchedFilesList

	//Mod051209AS
	for (BaselinePreferenceMapType::iterator myI = BaseAPrefs.begin(); myI != BaseAPrefs.end(); myI++)
	{
		delete (*myI).second;
	}
	for (BaselinePreferenceMapType::iterator myI = BaseBPrefs.begin(); myI != BaseBPrefs.end(); myI++)
	{
		delete (*myI).second;
	}
	//End of Mod051209AS
}

// Description: Calculates the value for the best possible alignment of file1 and file2
//         Essentially doing a sequence alignment in linear space via divide and conquer
// Revision  Date     Author  Modification
// Rev-1     Fall 08  HG      Original author
// Rev-2     Fall 08  VN      Only compare two files that have the same 
//                              sort name (excluding the path)
//                              Two files are matched if and only if they have 
//                              the same sort name.
// Rev-3     5/12/09  VN	  Mod051209AS: Included memory leak fixes provided by Aaron Shumate of NGC
int DiffTool::compareFileNames(string file1, string file2)
{
	int delta = 1;
	int mismatchCost = 1;

	if (CUtil::ExtractFilename(file1).compare(CUtil::ExtractFilename(file2)) != 0)
		return MAX_MISMATCH_COST;

	int** B = new int*[(int)file1.size()+1];	//Then need to go through each and initialize two size 2
	//Initialize B[i,0] = i*delta
	for (int i = 0; i <= (int)file1.size(); i++)
	{
		B[i] = new int[2];
		B[i][0] = i * delta;
	}
	for (int j = 1; j <= (int)file2.size(); j++)
	{
		B[0][1] = j * delta;
		for (int i = 1; i <= (int)file1.size(); i++)
		{
			int ourMatchCost = (file1[i] == file2[j]) ? 0 : mismatchCost;
			B[i][1] = min(ourMatchCost + B[i-1][0],
				min(delta + B[i-1][1],delta + B[i][0]));
		}
		for (int i = 1; i <= (int)file1.size(); i++)
		{
			B[i][0] = B[i][1];
		}
	}
	//The optimal alignment value is in B[file1.size(),1]
	int rValue = B[(int)file1.size()][1];
	//Mod051209AS
	for (int i = 0 ; i <= (int)file1.size() ; i++)
	{
		delete[] B[i];
	}
	delete[] B;
	//End of Mod051209AS
	return rValue;
}

/** Handles the calls to the Main UCC library to read input files.
*/
int DiffTool::handleReadInputFiles()
{
	// ------------------   Duplication Modification -----------------------
	// Flag to indicate if the files are to be read from filelist<A|B>.txt 
	// or from the parameters mentioned at command line
	vector <string> listFileNamesA;
	vector <string> listFileNamesB;

	if (use_CommandLine)
	{
		CUtil::ListAllFiles(dirnameA, listFilesToBeSearched,listFileNamesA);

		// Baseline B
		CUtil::ListAllFiles(dirnameB, listFilesToBeSearched,listFileNamesB);

		BaselineFileName1 = BaselineFileName2 = "";
	}

	if (!ReadAllFile(listFileNamesA, BaselineFileName1,true) || !ReadAllFile(listFileNamesB, BaselineFileName2,false))
		return 0;

	return 1;
}

/** Parses the command line for the Diff Tool
    Added parameter -cf to allow ClearCase files, Mod052409_1VN
*/
void DiffTool::parse_commandLine(int argc, char *argv[])
{
	duplicate_threshold = 0;	//Default Duplicate Files Threshold
	lsloc_truncate = 10000;		//Default LSLOC Maximum characters for truncation (0=no truncation)
	for (int i = 1; i < argc; i++)
	{
		string arg (argv[i]);
	// ------------------   Duplication Modification -----------------------
		// Check for command line parameter - 'dir' and read both the directory names
		// following it and the extract the names of the file extensions to be searched
		if (arg == "-dir")
		{
			if (i + 3 > argc)
			{
				string err = "Error: Unable to parse command line args";
				cout << err << endl;
				CUtil::AddError(err);
				show_usage(string(argv[0]));
			}

			i++;
			// Extract the directory name for Baseline A
			dirnameA = argv[i];
			i++;
			// Extract the directory name for Baseline B
			dirnameB = argv[i];
			i++;
			use_CommandLine = true;

			// Extract the names of the all file extensions to be searched
			for (; i<argc; i++)
			{
				arg = argv[i];
				// Command line arguments can be mentioned in any sequence.
				// Thus search for them till you do not come across the end of arguments or any one of 
				// the following mentioned.
				if ((arg == "-i1") || (arg == "-i2") || (arg == "-t") || (arg == "-d") || (arg == "-P"))
					break;
				else
					listFilesToBeSearched.push_back(arg);	 		
			}

			if (listFilesToBeSearched.size() == 0) // add all files as the default
			{
				listFilesToBeSearched.push_back("*.*");
			}
		}

		// Return from the loop if all arguments have been processed.
		if (i == argc)
			return;

		if (arg == "-i1")
		{	//Search for baseline A
			if (argc >= (i+1))
			{
				ifstream infile;
				infile.open(argv[i+1], ifstream::in);
				infile.close();
				if (infile.fail())
				{
					//File did not exist
					string err = "Error: Unable to open baseline file (";
					err += argv[i+1];
					err += ")";
					cout << err << endl;
					CUtil::AddError(err);
					show_usage(string(argv[0]));
				}
				else
				{
					BaselineFileName1 = string(argv[i+1]);
				}
				i++;
			}
			else
			{
				show_usage(string(argv[0]));
			}
		}
		else if (arg == "-i2")
		{
			if (argc >= (i+1))
			{
				ifstream infile;
				infile.open(argv[i+1], ifstream::in);
				infile.close();
				if (infile.fail())
				{
					//File did not exist
					string err = "Error: Unable to open baseline file (";
					err += argv[i+1];
					err += ")";
					cout << err << endl;
					CUtil::AddError(err);
					show_usage(string(argv[0]));
				}
				else
				{
					BaselineFileName2 = string(argv[i+1]);
				}
				i++;
			}
			else
			{
				show_usage(string(argv[0]));
			}
		}
		else if (arg == "-t")
		{
			if (argc >= (i+1))
			{
				double myMatch = atof(argv[i+1]);
				if (myMatch >= 0 && myMatch <= 100)
				{
					match_threshold = myMatch;
				}
				else
				{
					show_usage(string(argv[0]));
				}
				i++;
			}
			else
			{
				show_usage(string(argv[0]));
			}
		}
		else if (arg == "-tdup")
		{
			if (argc >= (i+1))
			{
				double myDup = atof(argv[i+1]);
				if (myDup >= 0 && myDup <= 100)
				{
					duplicate_threshold = myDup;
				}
				else
				{
					show_usage(string(argv[0]));
				}
				i++;
			}
			else
			{
				show_usage(string(argv[0]));
			}
		}
		else if (arg == "-trunc")
		{
			if (argc >= (i+1))
			{
				int myTrunc = atoi(argv[i+1]);
				if (myTrunc >= 0)
				{
					lsloc_truncate = myTrunc;
				}
				else
				{
					show_usage(string(argv[0]));
				}
				i++;
			}
			else
			{
				show_usage(string(argv[0]));
			}
		}
		else if (arg == "-P")
		{
			use_SLOC = false;
		}
		else if (arg == "-d")
		{
			//ignore
		}
		else if (arg == "-cf")
		{
			clearCaseFile = true;
		}
		else
		{
			show_usage(string(argv[0]));
			break;
		}
	}
}
